package com.xueyi.core.utils;

import com.alibaba.fastjson2.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.xueyi.core.constants.SystemCode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.lang3.time.DateUtils;

import java.util.Date;

/**
 * @author 俞烨
 * @version 1.0
 * @description: JWT工具类
 * @date 2024/2/5 18:39
 */
public class JWTUtil {

    /**
     * 秘钥信息
     */
    private static final String JWT_SECRET = "!@#$LuQiQiNb*()_)";

    /**
     * 解析内容
     *
     * @param sign
     * @return
     */
    public static Result parseSign(String sign) {

        // 通过签名生成验证对象
        JWTVerifier jwtVerifier = null;
        try {
            jwtVerifier = JWT.require(Algorithm.HMAC256(JWT_SECRET)).build();
            return new Result(jwtVerifier.verify(sign),
                    SystemCode.SUCCESS);
        } catch (Exception e) {
            return new Result(null,
                    SystemCode.USER_NOT_LOGIN);
        }
    }

    /**
     * 生成JWT信息
     *
     * @param baseUser
     * @param token
     * @param pastTime
     * @return
     */
    public static <T> String createJwtToken(T baseUser, String token, Date pastTime) {

        return JWT.create()
                .withClaim("userInfo", JSON.toJSONString(baseUser))
                .withClaim("token", token)
                .withExpiresAt(pastTime)
                .sign(Algorithm.HMAC256(JWT_SECRET));
    }

    /**
     * 判断是否需要更换sign信息
     *
     * @param parseSignResult
     * @return
     */
    public static <T> ChangeSignResult changeJwtSign(Result parseSignResult, Class<T> clazz) {

        Date expiresAt = parseSignResult.getDecodedJWT().getExpiresAt();
        String sign = null;
        if (expiresAt.compareTo(new Date(new Date().getTime() + 600 * 1000)) < 1) {
            sign = createJwtToken(JSON.parseObject(parseSignResult.claim("userInfo").asString(),
                            clazz),
                    parseSignResult.claim("token").asString(),
                    DateUtils.addDays(new Date(), 3));
        }
        return ChangeSignResult.builder()
                .sign(sign)
                .build();
    }


    /**
     * 是否需要更换Result信息
     */
    @Data
    @Builder
    public static class ChangeSignResult {

        private String sign;
    }

    @AllArgsConstructor
    @Builder
    @Data
    public static class Result {

        private DecodedJWT decodedJWT;
        private Integer code;

        public Claim claim(String key) {
            return decodedJWT.getClaim(key);
        }
    }
}
